#!/usr/bin/env/ python
# -*- coding:utf-8 -*-

__author__ = 'shouke'

import os
import time
import  re
import  configparser

from collections import deque
from paramiko.client import AutoAddPolicy
from paramiko.client import SSHClient
from otherTools import OtherTools
from log import logger

class MySSHClient:
    data_queue = deque()
    def __init__(self):
        self.ssh_client = SSHClient()
        config = configparser.ConfigParser()
        config.read('./conf/account.conf', encoding='utf-8')
        self.user_id = config['ACCOUNT']['user_id']
        self.passwd = config['ACCOUNT']['pwd']
        self.login_user_choice = config['ACCOUNT']['login_user_choice']

    # 连接登录
    def connect(self, hostname, port, username, password, host_via_by_bastion=''):
        try:
            self.ssh_client.set_missing_host_key_policy(AutoAddPolicy())
            self.ssh_client.connect(hostname=hostname, port=port, username=username, password=password, timeout=30)
            channel = self.ssh_client.invoke_shell()
            channel.settimeout(20) # 读、写操作超时时间，10秒

            ############################## 定制化开发 ##############################
            if host_via_by_bastion:
                logger.info('正在通过堡垒机：%s 访问目标机：%s' % (hostname, host_via_by_bastion))
                host_via_by_bastion = host_via_by_bastion + '\n'

                prompt_input_list = [{'Please enter your ID':'%s\n' % self.user_id}, {'Please enter your password': '%s\n' % self.passwd}, {'Please select your app ip':host_via_by_bastion}, {'select your user for login':'%s\n' % self.login_user_choice}]
                end_flag1 = ']$'
                end_flag2 = ']#'

                stdout = ''  # 存放每次执行读取的内容
                for item in prompt_input_list:
                    prompt = list(item.keys())[0]
                    input = item[prompt]

                    flag = False
                    while stdout.find(prompt) == -1:
                        try:
                            stdout += channel.recv(65535).decode('utf-8')#.decode('utf-8')
                            flag = True
                        except Exception as e:
                            logger.error('通过堡垒机：%s 访问目标机：%s 失败：%s' % (hostname, host_via_by_bastion, e))
                            flag = False
                            break
                    if flag:
                        channel.send(input)
                    else: # 未找到了对应提示
                        return [False, '通过堡垒机：%s 访问目标机：%s 失败，可能是读取命令返回结果超时，或者没找到对应输入提示'  % (hostname, host_via_by_bastion)]

                flag = False
                while not (stdout.rstrip().endswith(end_flag1) or stdout.rstrip().endswith(end_flag2)):
                    try:
                        stdout = channel.recv(2048).decode('utf-8')
                        flag = True
                    except Exception as e:
                        logger.error('通过堡垒机：%s 访问目标机：%s 失败：%s' % (hostname, host_via_by_bastion, e))
                        flag = False
                        break
                if flag:
                     return [True, '']
                else: # 未找到了对应提示
                    return [False, '没出现成功登录提示符 ]$ 或 ]# ']
            channel.close()
            return  [True, '']
        except Exception as e:
            return [False, '%s' % e]

    # 远程执行命令（用于在非docker容器主机上执行性能数据采集命令）
    def exec_command(self, command, target_host, bastion_host):
        try:
            channel = self.ssh_client.invoke_shell()
            channel.settimeout(300) # 读、写操作超时时间，30秒

            end_flag1 = ']$'
            end_flag2 = ']#'
            # ############################## 定制化开发 ##############################
            # if bastion_host != '':
            #     logger.info('正在通过堡垒机：%s 访问目标机：%s' % (bastion_host, target_host))
            #     target_host_input = target_host + '\n'
            #     prompt_input_list = [{'Please enter your ID':'%s\n' % self.user_id}, {'Please enter your password': '%s\n' % self.passwd}, {'Please select your app ip':target_host_input}, {'select your user for login':'%s\n' % self.login_user_choice}]
            #
            #     stdout = ''  # 存放每次执行读取的内容
            #     for item in prompt_input_list:
            #         prompt = list(item.keys())[0]
            #         input = item[prompt]
            #
            #         flag = False
            #         while stdout.find(prompt) == -1:
            #             try:
            #                 stdout += channel.recv(65535).decode('utf-8')
            #                 flag = True
            #             except Exception as e:
            #                 logger.error('通过堡垒机：%s 访问目标机：%s 失败：%s' %  (bastion_host, target_host, e))
            #                 flag = False
            #                 break
            #         if flag:
            #             channel.send(input)
            #         else: # 未找到了对应提示
            #             logger.error('通过堡垒机：%s 访问目标机：%s 失败，可能是读取命令返回结果超时，或者没找到对应输入提示'  %  (bastion_host, target_host))
            #             # return [False, '通过堡垒机：%s 访问目标机：%s 失败，可能是读取命令返回结果超时，或者没找到对应输入提示'  %  (bastion_host, target_host)]
            #             return
            #
            #     while not (stdout.rstrip().endswith(end_flag1) or stdout.rstrip().endswith(end_flag2)):
            #         try:
            #             stdout = channel.recv(2048).decode('utf-8')
            #         except Exception as e:
            #             logger.error('通过堡垒机：%s 访问目标机：%s 失败：没出现成功登录提示符 ]$ 或 ]#' % (bastion_host, target_host))
            #             return

            channel.send(command+'\n')
            logger.info('在目标机上（IP: %s）执行命令：%s' % (target_host, command))

            stdout = ''
            command_res = ''  # 存放每次执行读取的内容
            flag_str_regex = re.compile('CPU\)\n\n\d\d:\d\d:\d\d\s+(.+)\n') # 代表一组数据开始的正则表达式
            is_first = True
            first_index = 0
            while not ((command_res.endswith(end_flag1) or command_res.endswith(end_flag2)) and not is_first):
                try:
                    command_res = channel.recv(2048)#.decode('utf-8')
                    stdout += command_res.decode('utf-8').replace('\r\r', '\n').replace('\r', '')
                except Exception as e:
                    logger.error('在目标机(IP: %s)上进行读取操作超时' % target_host)
                    break

                if is_first:
                    flag_str = re.findall(flag_str_regex, stdout)
                    if flag_str:
                        flag_str = flag_str[0]
                        flag_str_regex2 = re.compile('\d\d:\d\d:\d\d\s+%s' % flag_str)
                        is_first = False
                    else:
                        command_res = command_res.decode('utf-8').strip()
                        continue

                result = re.findall(flag_str_regex2, stdout) # 代表一组数据开始的字符串，第1次出现
                if result:
                    first_index = stdout.find(result[0])  # 查找代表一组数据开始的字符串，第一次出现的位置
                    temp_index = first_index + len(result[0]) + 1
                    temp_stdout = stdout[temp_index:]
                    result = re.findall(flag_str_regex2, temp_stdout) # 代表一组数据开始的字符串，第二次出现
                    if result: # 代表一组数据开始的字符串，第二次出现
                        second_index = stdout.find(result[0], temp_index)
                        if second_index != -1: #一组数据开始的字符串，第二次出现,,表明找到了一组数据
                            temp_stdout = stdout[first_index:second_index] # 存放一组数据
                            stdout = stdout[second_index:] # 去掉已取到的第一组数据
                            MySSHClient.data_queue.append((target_host, time.strftime('%Y-%m-%d', time.localtime()), temp_stdout.split('\n\n')))

                        else:
                            logger.error('意想不到的错误')
                            exit()
                command_res = command_res.decode('utf-8').strip()

            # 添加最后2组数据
            second_index = stdout.find('Average')
            if second_index != -1:
                MySSHClient.data_queue.append((target_host,time.strftime('%Y-%m-%d', time.localtime()), stdout[first_index:second_index].strip().split('\n\n')))
                # MySSHClient.data_queue.append((target_host,time.strftime('%Y-%m-%d', time.localtime()), stdout[second_index:].strip().split('\n\n')))
            else:
                MySSHClient.data_queue.append((target_host,time.strftime('%Y-%m-%d', time.localtime()), stdout[first_index:].split('\n\n')))
            channel.close()
        except Exception as e:
           logger.error('针对目标机：%s 执行命令: %s 出错 %s' % (target_host, command, e))

    # 远程执行命令（用于在docker容器主机执行性能数据采集命令）
    def exec_command_in_docker_container(self, command, target_host, bastion_host, collector_sh_script):
        try:
            channel = self.ssh_client.invoke_shell()
            channel.settimeout(300) # 读、写操作超时时间

            end_flag1 = ']$'
            end_flag2 = ']#'
            ############################## 定制化开发 ##############################
            if bastion_host != '':
                logger.info('正在通过堡垒机：%s 访问目标机：%s' % (bastion_host, target_host))
                target_host_input = target_host + '\n'
                prompt_input_list = [{'Please enter your ID':'%s\n' % self.user_id}, {'Please enter your password': '%s\n' % self.passwd}, {'Please select your app ip':target_host_input}, {'select your user for login':'%s\n' % self.login_user_choice}]

                stdout = ''  # 存放每次执行读取的内容
                for item in prompt_input_list:
                    prompt = list(item.keys())[0]
                    input = item[prompt]

                    flag = False
                    while stdout.find(prompt) == -1:
                        try:
                            stdout += channel.recv(65535).decode('utf-8')
                            flag = True
                        except Exception as e:
                            logger.error('通过堡垒机：%s 访问目标机：%s 失败：%s' %  (bastion_host, target_host, e))
                            flag = False
                            break
                    if flag:
                        channel.send(input)
                    else: # 未找到了对应提示
                        logger.error('通过堡垒机：%s 访问目标机：%s 失败，可能是读取命令返回结果超时，或者没找到对应输入提示'  %  (bastion_host, target_host))
                        # return [False, '通过堡垒机：%s 访问目标机：%s 失败，可能是读取命令返回结果超时，或者没找到对应输入提示'  %  (bastion_host, target_host)]
                        return

                while not (stdout.rstrip().endswith(end_flag1) or stdout.rstrip().endswith(end_flag2)):
                    try:
                        stdout = channel.recv(65535).decode('utf-8')
                    except Exception as e:
                        logger.error('通过堡垒机：%s 访问目标机：%s 失败：没出现成功登录提示符 ]$ 或 ]#' % (bastion_host, target_host))
                        return

                logger.info('在目标机：%s 上执行删除collector.sh脚本操作' % target_host)
                channel.send('rm -rf collector.sh\n')
                for line in collector_sh_script:
                    stdout = ''
                    channel.send("echo '%s' >> collector.sh\n" % line)
                    while not (stdout.rstrip().endswith(end_flag1) or stdout.rstrip().endswith(end_flag2)):
                        try:
                            stdout = channel.recv(65535).decode('utf-8')
                        except Exception as e:
                            logger.error('在目标机：%s 上执行删除collector.sh脚本失败' % target_host)
                            return

                stdout = '' # 存储命令输出
                logger.info('在目标机：%s 上替换collector.sh脚本中的目标字符串' % target_host)
                channel.send('sed -i \'s/@doubleQuotation@/"/g\' collector.sh\n')
                channel.send('sed -i "s/@singleQuotation@/\'/g" collector.sh\n')
                while not (stdout.rstrip().endswith(end_flag1) or stdout.rstrip().endswith(end_flag2)):
                    try:
                        stdout = channel.recv(65535).decode('utf-8')
                    except Exception as e:
                        logger.error('在目标机：%s 上替换collector.sh脚本中的目标字符串失败' % target_host)
                        return

                channel.send(command+'\n')
                logger.info('在目标机上（IP: %s）执行命令：%s' % (target_host, command))

                stdout = ''
                command_res = ''  # 存放每次执行读取的内容
                is_find = False # 未找到数据
                start_index = 0  # 数据组开始索引
                while not ((command_res.endswith(end_flag1) or command_res.endswith(end_flag2)) and is_find):
                    try:
                        command_res = channel.recv(65535)
                        stdout += command_res.decode('utf-8').replace('\r\r', '\n').replace('\r', '')
                    except Exception as e:
                        logger.error('在目标机(IP: %s)上进行读取操作超时' % target_host)
                        break

                    index = stdout.find('start_collecting') # 代表一组数据开始的字符串
                    if index != -1:
                        start_index = index + len('start_collecting')
                        is_find = True

                    index = stdout.find('end_collecting') # 代表一组数据结束的字符串
                    if index != -1:
                        single_group_data = stdout[start_index:index]
                        data_group_list = []
                        for item in single_group_data.strip('||').replace('\n', '').split('||'):
                            item = eval(item)
                            for key, value in item.items():
                                temp_str = ''
                                if key == 'cpu_limit': # CPU限制
                                    temp_str += value['cur_time'] + '@' + value['cur_date'] + ' CPU_LIMIT cfs_period_us cfs_quota_us shares rt_period_us rt_runtime_us throttled_time nr_throttled\n'
                                    temp_str += '%s@%s all %s %s %s %s %s %s %s' % (value['cur_time'], value['cur_date'], value['cfs_period_us'], value['cfs_quota_us'], value['shares'],
                                                                                    value['rt_period_us'], value['rt_runtime_us'],value['throttled_time'], value['nr_throttled'])
                                    data_group_list.append(temp_str)
                                elif key == 'cpu_usage': # CPU使用
                                    temp_str += value['cpu_usage2']['cur_time'] + '@' + value['cpu_usage2']['cur_date'] + ' CPU %cpu %system %user throttled_time nr_throttled\n'

                                    # 计算CPU使用率
                                    clk_tck =  value['clk_tck'] # 1秒钟的滴答数 hz
                                    host_cpu_total = value['cpu_usage2']['host_cpu_total'] - value['cpu_usage1']['host_cpu_total'] # 单位 jiffies
                                    container_cpu_usage = value['cpu_usage2']['container_cpu_usage'] - value['cpu_usage1']['container_cpu_usage'] # 单位 纳秒
                                    containe_user_cpu_usage = value['cpu_usage2']['containe_user_cpu_usage'] - value['cpu_usage1']['containe_user_cpu_usage'] # 单位 jiffies
                                    container_system_cpu_usage = value['cpu_usage2']['container_system_cpu_usage'] - value['cpu_usage1']['container_system_cpu_usage'] # 单位 jiffies

                                    cpu_core_num = len(value['cpu_usage2']['container_percup_usage'].strip().split())
                                    if host_cpu_total: # 如果不为0
                                        host_cpu_total = host_cpu_total * 1.0/clk_tck * pow(10, 9)  # 1秒等于10^9纳秒，jiffies = 1 / clk_tck
                                        # container_cpu_usage = container_cpu_usage / host_cpu_total * 100 * cpu_core_num # 单核cpu使用率均值 x cpu核数
                                        # containe_user_cpu_usage = containe_user_cpu_usage * 10 * pow(10, 6) / host_cpu_total * 100 * cpu_core_num
                                        # container_system_cpu_usage = container_system_cpu_usage * 10 * pow(10, 6) / host_cpu_total * 100 * cpu_core_num
                                        container_cpu_usage = (container_cpu_usage / host_cpu_total) * 100 * cpu_core_num # 单核cpu使用率均值 * 使用的cpu核数
                                        containe_user_cpu_usage = containe_user_cpu_usage * 1.0/clk_tck * pow(10, 9) / host_cpu_total * 100 * cpu_core_num
                                        container_system_cpu_usage = container_system_cpu_usage * 1.0/clk_tck * pow(10, 9) / host_cpu_total * 100 * cpu_core_num
                                    else:
                                        container_cpu_usage = 0
                                        containe_user_cpu_usage = 0
                                        container_system_cpu_usage = 0

                                    temp_str += '%s@%s all %.2f %.2f %.2f %s %s' % (value['cpu_usage2']['cur_time'], value['cpu_usage2']['cur_date'], container_cpu_usage, container_system_cpu_usage, containe_user_cpu_usage,
                                                                              value['cpu_usage2']['throttled_time'], value['cpu_usage2']['nr_throttled'])
                                    data_group_list.append(temp_str)
                                elif key == 'mem_swap': # 内存和SWAP
                                    temp_str += value['mem_swap_usage2']['cur_time'] + '@' +  value['mem_swap_usage2']['cur_date'] + ' mem_usage  %mem mem_real_usage %mem_real_usage mem_limit memsw_usage memsw_limit rss cache swap\n'
                                    if value['mem_swap_limit']['mem_limit'] == 9223372036854775807: # 9223372036854775807要做成配置
                                        mem_limit = value['mem_swap_usage2']['host_mem_total'] * 1024 # host_mem_total 单位kb
                                    else:
                                        mem_limit = value['mem_swap_limit']['mem_limit']

                                    if value['mem_swap_limit']['memsw_limit'] == 9223372036854775807:
                                        memsw_limit = mem_limit + value['mem_swap_usage2']['host_swap_total'] * 1024 # host_swap_total 单位kb
                                    else:
                                        memsw_limit = value['mem_swap_limit']['memsw_limit']

                                    mem_usage_percent = value['mem_swap_usage2']['mem_usage'] / mem_limit * 100.0
                                    mem_real_usage = value['mem_swap_usage2']['mem_usage'] - value['mem_swap_usage2']['active_file'] \
                                                     - value['mem_swap_usage2']['inactive_file']
                                    mem_real_usage_percent = mem_real_usage / mem_limit * 100.0

                                    temp_str += '%s@%s %s %.2f %s %.2f %s %s %s %s %s %s' % (value['mem_swap_usage2']['cur_time'],
                                                value['mem_swap_usage2']['cur_date'], value['mem_swap_usage2']['mem_usage'],
                                                mem_usage_percent, mem_real_usage, mem_real_usage_percent, mem_limit, value['mem_swap_usage2']['memsw_usage'], memsw_limit,
                                                value['mem_swap_usage2']['rss'], value['mem_swap_usage2']['cache'], value['mem_swap_usage2']['swap'])
                                    data_group_list.append(temp_str)

                                    date_time1 = value['mem_swap_failcnt1']['cur_date'] + ' ' + value['mem_swap_failcnt1']['cur_time']
                                    date_time2 = value['mem_swap_failcnt2']['cur_date'] + ' ' + value['mem_swap_failcnt2']['cur_time']
                                    timetuple1 = time.strptime(date_time1, '%Y-%m-%d %H:%M:%S')
                                    timetuple2 = time.strptime(date_time2, '%Y-%m-%d %H:%M:%S')
                                    second = time.mktime(timetuple2)-time.mktime(timetuple1)
                                    if second == 0:
                                        second = 1

                                    temp_str = ''
                                    temp_str += value['mem_swap_failcnt2']['cur_time'] + '@' +  value['mem_swap_failcnt2']['cur_date'] + ' mem_failcnt/s memsw_failcnt/s kmem_failcnt/s kmem_tcp_failcnt/s oom_kill_disable under_oom\n'
                                    mem_failcnt = (value['mem_swap_failcnt2']['mem_failcnt'] - value['mem_swap_failcnt1']['mem_failcnt']) / second
                                    memsw_failcnt = (value['mem_swap_failcnt2']['memsw_failcnt'] - value['mem_swap_failcnt1']['memsw_failcnt']) / second
                                    kmem_failcnt = (value['mem_swap_failcnt2']['kmem_failcnt'] - value['mem_swap_failcnt1']['kmem_failcnt']) / second
                                    kmem_tcp_failcnt = (value['mem_swap_failcnt2']['kmem_tcp_failcnt'] - value['mem_swap_failcnt1']['kmem_tcp_failcnt']) / second
                                    temp_str += '%s@%s %.0f %.0f %.0f %.0f %s %s' % (value['mem_swap_failcnt2']['cur_time'],
                                                value['mem_swap_failcnt2']['cur_date'], mem_failcnt , memsw_failcnt, kmem_failcnt, kmem_tcp_failcnt,
                                                value['mem_swap_failcnt2']['oom_kill_disable'], value['mem_swap_failcnt2']['under_oom'])
                                    data_group_list.append(temp_str)

                                    date_time1 = value['mem_swap_usage2']['cur_date'] + ' ' + value['mem_swap_usage1']['cur_time']
                                    date_time2 = value['mem_swap_usage2']['cur_date'] + ' ' + value['mem_swap_usage2']['cur_time']
                                    timetuple1 = time.strptime(date_time1, '%Y-%m-%d %H:%M:%S')
                                    timetuple2 = time.strptime(date_time2, '%Y-%m-%d %H:%M:%S')
                                    second = time.mktime(timetuple2)-time.mktime(timetuple1)
                                    if second == 0:
                                        second = 1

                                    temp_str = ''
                                    temp_str += value['mem_swap_usage2']['cur_time'] + '@' +  value['mem_swap_usage2']['cur_date'] + ' pgpgin/s pgpgout/s pgfault/s pgmajfault/s\n'
                                    pgpgin = (value['mem_swap_usage2']['pgpgin'] - value['mem_swap_usage1']['pgpgin']) / second
                                    pgpgout = (value['mem_swap_usage2']['pgpgout'] - value['mem_swap_usage1']['pgpgout']) / second
                                    pgfault = (value['mem_swap_usage2']['pgfault'] - value['mem_swap_usage1']['pgfault']) / second
                                    pgmajfault = (value['mem_swap_usage2']['pgmajfault'] - value['mem_swap_usage1']['pgmajfault']) / second

                                    temp_str += '%s@%s  %.0f %.0f %.0f %.0f' % (value['mem_swap_usage2']['cur_time'],
                                                value['mem_swap_usage2']['cur_date'], pgpgin, pgpgout, pgfault, pgmajfault)
                                    data_group_list.append(temp_str)
                                elif key == 'blkio':
                                    date_time1 = value['blkio1']['cur_date'] + ' ' + value['blkio1']['cur_time']
                                    date_time2 = value['blkio2']['cur_date'] + ' ' + value['blkio2']['cur_time']
                                    timetuple1 = time.strptime(date_time1, '%Y-%m-%d %H:%M:%S')
                                    timetuple2 = time.strptime(date_time2, '%Y-%m-%d %H:%M:%S')
                                    second = time.mktime(timetuple2)-time.mktime(timetuple1)
                                    if second == 0:
                                        second = 1

                                    temp_str = ''
                                    temp_str += value['blkio2']['cur_time'] + '@' +  value['blkio2']['cur_date'] + ' tps rtps wtps rate rrate wrate\n'

                                    io_dic1, io_dic2 = {'Read':0, 'Write':0, 'Type':0}, {'Read':0, 'Write':0, 'Type':0}
                                    io_serviced_list = value['blkio1']['io_serviced']
                                    for item in io_serviced_list:
                                        temp = item.split(':')
                                        io_dic1[temp[2]] += int(temp[3])

                                    io_serviced_list = value['blkio2']['io_serviced']
                                    for item in io_serviced_list:
                                        temp = item.split(':')
                                        io_dic2[temp[2]] += int(temp[3])

                                    total_io_serviced1 = io_dic1['Read'] + io_dic1['Write']
                                    total_io_serviced2 = io_dic2['Read'] + io_dic2['Write']
                                    iotps = (total_io_serviced2 - total_io_serviced1) / second
                                    rtps = (io_dic2['Read'] - io_dic1['Read']) / second
                                    wtps = (io_dic2['Write'] - io_dic1['Write']) / second

                                    io_dic1, io_dic2 = {'Read':0, 'Write':0, 'Type':0}, {'Read':0, 'Write':0, 'Type':0}
                                    io_serviced_bytes_list = value['blkio1']['io_service_bytes']
                                    for item in io_serviced_bytes_list:
                                        temp = item.split(':')
                                        io_dic1[temp[2]] += int(temp[3])

                                    io_serviced_bytes_list = value['blkio2']['io_service_bytes']
                                    for item in io_serviced_bytes_list:
                                        temp = item.split(':')
                                        io_dic2[temp[2]] += int(temp[3])
                                    total_io_serviced_bytes1 = io_dic1['Read'] + io_dic1['Write']
                                    total_io_serviced_bytes2 = io_dic2['Read'] + io_dic2['Write']
                                    iorate = (total_io_serviced_bytes2 - total_io_serviced_bytes1) / second / 1024
                                    rrate = (io_dic2['Read'] - io_dic1['Read']) / second
                                    wrate = (io_dic2['Write'] - io_dic1['Write']) / second

                                    temp_str += '%s@%s  %.0f %.0f %.0f %.0f %.0f %.0f' % (value['blkio2']['cur_time'],
                                                value['blkio2']['cur_date'], iotps, rtps, wtps, iorate, rrate, wrate)

                                    data_group_list.append(temp_str)

                        start_index = index + len('end_collecting')
                        stdout = stdout[start_index:]
                        MySSHClient.data_queue.append((target_host, '', data_group_list))
                    command_res = command_res.decode('utf-8').strip()

            stdout = ''
            channel.send('rm -rf collector.sh\n')
            while not (stdout.rstrip().endswith(end_flag1) or stdout.rstrip().endswith(end_flag2)):
                try:
                    stdout = channel.recv(65535).decode('utf-8')
                except Exception as e:
                    logger.error('在目标机：%s 上执行collector.sh脚本删除操作' % target_host)
                    return
            channel.close()
        except Exception as e:
            logger.error('针对目标机：%s 执行命令: %s 出错 %s' % (target_host, command, e))


    # 下载文件(非目录文件)
    def download_file(self, remotepath, localpath):
        try:
            localpath = os.path.abspath(localpath)
            localpath = localpath.replace('\t', '/t').replace('\n', '/n').replace('\r', '/r').replace('\b', '/b') # 转换特殊字符
            localpath = localpath.replace('\f', '/f')
            logger.info('转换后的本地目标路径为：%s' % localpath)
            head, tail = os.path.split(localpath)
            if not tail:
                logger.warn('下载文件：%s 到本地：%s失败，本地文件名不能为空' % (remotepath, localpath))
                return [False, '下载文件：%s 到本地：%s失败，本地文件名不能为空' % (remotepath, localpath)]
            if not os.path.exists(head):
                logger.warn('本地路径：%s不存在，正在创建目录' % head)
                OtherTools().mkdirs_once_many(head)

            sftp_client = self.ssh_client.open_sftp()
            logger.info('正在下载远程文件：%s 到本地：%s' % (remotepath, localpath))
            sftp_client.get(remotepath, localpath)
            sftp_client.close()
            return [True, '']
        except Exception as e:
            logger.error('下载文件：%s 到本地：%s 出错:%s' % (remotepath, localpath, e))
            return [False, '下载文件：%s 到本地：%s 出错:%s' % (remotepath, localpath, e)]

    # 上传文件(非目录文件）
    def upload_file(self, localpath, remotepath):
        try:
            localpath = localpath.rstrip('\\').rstrip('/')
            localpath = localpath.replace('\t', '/t').replace('\n', '/n').replace('\r', '/r').replace('\b', '/b') # 转换特殊字符
            localpath = localpath.replace('\f', '/f')
            localpath = os.path.abspath(localpath)
            logger.info('转换后的本地文件路径为：%s' % localpath)

            remotepath = remotepath.rstrip('\\').rstrip('/')
            head, tail = os.path.split(localpath)
            if not tail:
                logger.error('上传文件：%s 到远程：%s失败，本地文件名不能为空' % (localpath, remotepath))
                return [False, '上传文件：%s 到远程：%s失败，本地文件名不能为空' % (localpath, remotepath)]
            if not os.path.exists(head):
                logger.error( '上传文件：%s 到远程：%s失败，父路径不存在' % (localpath, remotepath, head))
                return [False, '上传文件：%s 到远程：%s失败，父路径不存在' % (localpath, remotepath, head)]

            if not (remotepath.startswith('/') or remotepath.startswith('.')):
                logger.error('上传文件：%s 到远程：%s失败，远程路径填写不规范%s' % (localpath, remotepath,remotepath))
                return [False, '上传文件：%s 到远程：%s失败，远程路径填写不规范%s' % (localpath, remotepath,remotepath)]
            sftp_client = self.ssh_client.open_sftp()
            head, tail = os.path.split(remotepath)

            head = sftp_client.normalize(head) # 规范化路径
            remotepath = head + '/' + tail
            logger.info('规范化后的远程目标路径：', remotepath)

            logger.info('正在上传文件：%s 到远程：%s' % (localpath, remotepath))
            sftp_client.put(localpath, remotepath)
            sftp_client.close()
            return [True, '']
        except Exception as e:
            logger.error('上传文件：%s 到远程：%s 出错:%s' % (localpath, remotepath, e))
            return [False, '上传文件：%s 到远程：%s 出错:%s' % (localpath, remotepath, e)]

    def close(self):
        self.ssh_client.close()

# 测试
# ssh_client = MySSHClient()
# ssh_client.connect(hostname='10.202.27.5', port=22, username='sflog', password='sf123456',target_host= '10.203.32.38')
# ssh_client.exec_command('export LC_TIME=\"POSIX\";sar -u ALL -P ALL -q -w -r -S -W -B -b -n EDEV -n DEV 1 1','10.203.32.38')
# ssh_client.connect(hostname='10.202.27.5', port=22, username='sflog', password='sf123456',target_host= '10.203.32.49')
# ssh_client.exec_command('export LC_TIME=\"POSIX\";sar -u ALL -P ALL -q -w -r -S -W -B -pd -b -n EDEV -n DEV 1 1')

# ssh_client.exec_command('sar 1 1>1.txt')
# ssh_client.exec_command('sz 1.txt')
# ssh_client.download_file('/home/appdeploy/1.txt', 'd:\\1.txt')
# logger.info(ssh_client.exec_command('sar 1 1')[1][1])
#
# logger.info(ssh_client.exec_command('ls')[1][1])
# ssh_client.exec_command('sar 1 1 > sar.txt')

# print(ssh_client.exec_command('ls\n')[1][1])
# ssh_client.close()

#
# # 测试
# ssh_client = MySSHClient()
# ssh_client.connect(hostname='192.168.1.102', port=22, username='root',password='huozhe')
# ssh_client.connect(hostname='10.202.64.52', port=22, username='appdeploy',password='sf123456')
# ssh_client1 = ssh_client.invoke()
# ssh_client.exec_command('cd /home;pwd')
# ssh_client.exec_command('ls -l')
#ssh_client.invokesell()
#
# #
# ssh_client.download_file('/root/dirForDownload/file', './test1.txt')
# ssh_client.download_file('/root/dirForDownload/file', '.\test2.txt')
# ssh_client.download_file('/root/dirForDownload/file', 'd:\\test3.txt')
# ssh_client.download_file('/root/dirForDownload/file', 'd:\test4.txt')
# ssh_client.download_file('/root/dirForDownload/file', 'd:\mytest4.txt')
# ssh_client.download_file('/root/dirForDownload/file', 'd:/test5.txt')
# ssh_client.download_file('/root/dirForDownload/file', 'd:\dir1\dir2\test6.txt')
#
#ssh_client.upload_file('E:\packagesForLastVersion\ddt-common-ws-0.0.1-SNAPSHOT.war','/app/war/DDT_CORE_CNSZ22_JETTY_APP_COMMON_02/webapps/ddt-common-ws-0.0.1-SNAPSHOT.war' )
# ssh_client.upload_file('./test1.txt','/root/test1.txt' )
# ssh_client.upload_file('d:\mytest4.txt','/root/mytestfile.txt' )
# ssh_client.upload_file('d:\dir1\dir2\test6.txt','./test6.txt' )
# ssh_client.close()

